// $Id: uuid.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2008-2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPCOM_UUID_HPP
#define XPCOM_UUID_HPP

#include <xpcom/config.hpp>
#ifndef XPCOM_NO_IOSTREAM
#include <iosfwd>
#include <ios>
#endif // XPCOM_NO_IOSTREAM
#include <xpcom/types.hpp>

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

namespace xpcom {

//
// XPCOM UUID class.
//
// This class is designed to be a POD type.
//
class XPCOM_DECL uuid
{
public:
    uint32_t    m0;
    uint16_t    m1;
    uint16_t    m2;
    uint8_t     m3[8];

    // nil-uuid instance
    static const uuid nil;

    // Flags that control output behaviors
    enum output_tag
    {
        // By default, uuid output is all upper-case except the 3rd segment.
        // For example, 'XXXXXXXX-XXXX-xxxx-XXXX-XXXXXXXXXXXX'.
        output_normal_case = 0,

        // All output characters are lower-case.
        // This flag should not be combined with output_upper_case.
        output_lower_case = 1 << 1,

        // All output characters are upper-case.
        // This flag should not be combined with output_lower_case.
        output_upper_case = 1 << 2,

        // Setting this flag will cause braces to be written.
        output_braces = 1 << 4
    };

    bool is_nil() const throw()
    {
        return (((uint32_t*)&m0)[0] == 0) &&
               (((uint32_t*)&m0)[1] == 0) &&
               (((uint32_t*)&m0)[2] == 0) &&
               (((uint32_t*)&m0)[3] == 0);
    }

    bool equal(const uuid& rhs) const throw()
    {
        return (((uint32_t*)&m0)[0] == ((uint32_t*)&rhs.m0)[0]) &&
               (((uint32_t*)&m0)[1] == ((uint32_t*)&rhs.m0)[1]) &&
               (((uint32_t*)&m0)[2] == ((uint32_t*)&rhs.m0)[2]) &&
               (((uint32_t*)&m0)[3] == ((uint32_t*)&rhs.m0)[3]);
    }

    int compare(const uuid& rhs) const throw();

    void swap(uuid& rhs) throw();

    // The string buffer will be parsed into the uuid data.
    // Format of the string must be 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
    // (which is 36 characters) or '{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'
    // (which is 38 characters).
    template <typename CharT>
    void from_str(const basic_string<CharT>& str);

    template <typename CharT>
    void from_str(const CharT* s, uint32_t n = static_cast<uint32_t>(-1));

    // Formats and writes the uuid to the given string buffer.
    // Exact output format is determined by output flags.
    template <typename CharT>
    void to_str(basic_string<CharT>& str, uint32_t flags = 0) const;

    string str(uint32_t flags = 0) const;
    wstring wstr(uint32_t flags = 0) const;
};

// Comparisons
inline bool operator==(const uuid& lhs, const uuid& rhs)
{
    return lhs.equal(rhs);
}

inline bool operator!=(const uuid& lhs, const uuid& rhs)
{
    return !(lhs == rhs);
}

inline bool operator<(const uuid& lhs, const uuid& rhs)
{
    return lhs.compare(rhs) < 0;
}

inline bool operator>(const uuid& lhs, const uuid& rhs)
{
    return lhs.compare(rhs) > 0;
}

inline bool operator<=(const uuid& lhs, const uuid& rhs)
{
    return lhs.compare(rhs) <= 0;
}

inline bool operator>=(const uuid& lhs, const uuid& rhs)
{
    return lhs.compare(rhs) >= 0;
}

// swap
inline void swap(uuid& lhs, uuid& rhs)
{
    lhs.swap(rhs);
}

// IO
#ifndef XPCOM_NO_IOSTREAM

template <typename CharT, typename Traits>
std::basic_istream<CharT, Traits>& operator>>(
        std::basic_istream<CharT, Traits>& is, uuid& rhs)
{
    basic_string<CharT> s;
    if (is >> s) {
        try {
            rhs.from_str(s);
        } catch (...) {
            is.setstate(std::ios_base::badbit);
        }
    }
    return is;
}

template <typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(
        std::basic_ostream<CharT, Traits>& os, const uuid& rhs)
{
    basic_string<CharT> s;
    rhs.to_str(s);
    return os << s;
}

#endif // XPCOM_NO_IOSTREAM

} // namespace xpcom

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // XPCOM_UUID_HPP
